// various movement strategies for monster

import java.util.LinkedList;

class MonsterAI extends AI {

    public MonsterAI(Map map, Game game) {
        super(map, game);
    }

    @Override
    public int[] move() {
        updatePos();
        return randomMove(monsterPos);
    }
}


// Simply move toward rogue without considering the map
class TowardChaste extends MonsterAI {

    public TowardChaste(Map map, Game game) {
        super(map, game);
    }

    @Override
    public int[] move() {
        updatePos();
        int[] direction = map.findDirection(monsterPos, roguePos); // toward direction
        if (map.isDirectionMoveable(monsterPos, direction)) return direction;
        return new int[]{0, 0};
    }
}

// Use A* algorithm to chaste the rogue with distance function: manhattan
// this method always follow the shortest path to the rogue.
class AStarManhattan extends MonsterAI {

    public AStarManhattan(Map map, Game game) {
        super(map, game);
    }

    // simply Move toward rogue using A* algorithm to find the shortest path
    @Override
    public int[] move() {
        updatePos();
        LinkedList<int[]> path = AStar(monsterPos, roguePos, true, map, "manhattan");
        if (path.size() < 2) return new int[]{0, 0};
        return map.findDirection(monsterPos, path.get(1));
    }

}

// Use A* algorithm to chaste the rogue with distance function: Chebyshev
class AStarChebyshev extends MonsterAI {

    public AStarChebyshev(Map map, Game game) {
        super(map, game);
    }

    // simply Move toward rogue using A* algorithm to find the shortest path
    @Override
    public int[] move() {
        updatePos();
        LinkedList<int[]> path = AStar(monsterPos, roguePos, true, map, "chebyshev");
        if (path.size() < 2) return new int[]{0, 0};
        return map.findDirection(monsterPos, path.get(1));
    }

}

// Use A* algorithm to chaste the rogue with distance function: Heuristic
// Its performance has been proven to be identical to AStarManhattan
class AStarHeuristic extends MonsterAI {

    public AStarHeuristic(Map map, Game game) {
        super(map, game);
    }

    // simply Move toward rogue using A* algorithm to find the shortest path
    @Override
    public int[] move() {
        updatePos();
        LinkedList<int[]> path = AStar(monsterPos, roguePos, true, map, "heuristic");
        if (path.size() < 2) return new int[]{0, 0};
        return map.findDirection(monsterPos, path.get(1));
    }

}

// This strategy have been proven identical to AStarManhattan, and is deprecated for usage.
// Always make the move that results in the shortest manhattan path from rogue
class ShortestOrthogonalDistance extends MonsterAI {

    public ShortestOrthogonalDistance(Map map, Game game) {
        super(map, game);
    }

    @Override
    public int[] move() {
        updatePos();
        int shortest = AStarLength(monsterPos, roguePos, false);
        int moveX = 0;
        int moveY = 0;
        for (int x = -1; x <= 1; x++) {
            for (int y = -1; y <= 1; y++) {
                if (map.isDirectionMoveable(monsterPos[0], monsterPos[1], x, y)) {
                    int[] attempt = new int[]{monsterPos[0] + x, monsterPos[1] + y};
                    int attemptLength = AStarLength(attempt, roguePos, false);
                    if (shortest > attemptLength) {
                        shortest = attemptLength;
                        moveX = x;
                        moveY = y;
                    }
                }
            }
        }
        return new int[]{moveX, moveY};
    }
}